﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ListView = System.Windows.Controls.ListView;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using Path = System.IO.Path;

namespace AdamDsk
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private List<DirectoryEntry> _entries;
        private List<Info> _files;
        private ListView _selected;
        private string _adamFile;
        private DskFile _disk;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnFind_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new OpenFileDialog();

            dlg.DefaultExt = ".dsk";

            if (dlg.ShowDialog(this) ?? false)
            {
                _adamFile = dlg.FileName;
                GetAdamFiles(dlg.FileName);
            }
        }

        private void GetAdamFiles(string filename)
        {
            if (string.IsNullOrEmpty(filename)) return;

            var file = new FileInfo(filename);

            try
            {
                _disk = new DskFile((uint)file.Length);
                var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                _disk.LoadFile(stream);
                stream.Close();

                txtImageName.Text = _disk.Directory.Header.Name;

                _entries = new List<DirectoryEntry>();
                foreach (var entry in _disk.Directory.Entries)
                {
                    if (entry != null)
                    {
                        if ((entry.DIR_ATTRIBUTES & DirectoryAttributes.NotAFile) == DirectoryAttributes.NotAFile)
                        {
                            //lblBlocksLeft.Text = BitConverter.ToUInt16(entry.DIR_LAST_COUNT, 0).ToString("N0");
                            lblBlocksLeft.Text =
                                (_disk.TotalBlocks - BitConverter.ToUInt32(entry.DIR_START_BLOCK, 0)).ToString("N0");
                            break;
                        }

                        if ((entry.DIR_ATTRIBUTES & DirectoryAttributes.PermanentlyProtected) !=
                            DirectoryAttributes.PermanentlyProtected)
                        {
                            _entries.Add(entry);
                        }
                    }
                }

                adamFiles.ItemsSource = _entries;
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString(), "ERROR");
            }

        }

        private System.Windows.Controls.ListView Selected
        {
            get { return _selected; }
            set
            {
                _selected = value;

                if (_selected == adamFiles)
                {
                    borderAdam.Background = Brushes.LightGray;
                    borderLocal.Background = Brushes.DarkGray;
                }
                else
                {
                    borderLocal.Background = Brushes.LightGray;
                    borderAdam.Background = Brushes.DarkGray;
                }
            }
        }

        private void files_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Selected = adamFiles;
        }

        private void F1_Tapped(object sender, RoutedEventArgs e)
        {
            Process.Start("http://adamwiki.info/ADAMDsk");
        }

        private void F2_Tapped(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show(this, "Are you sure you want to leave ADAMDsk?", "Question", MessageBoxButton.YesNo,
                    MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                Close();
            }
        }

        private void F4_Tapped(object sender, RoutedEventArgs e)
        {
            if (Selected == adamFiles)
                GetAdamFiles(_adamFile);

            else
                LoadFiles();
        }

        private void F5_Tapped(object sender, RoutedEventArgs e)
        {
            if (Selected == adamFiles) CopyFromAdam();
            else CopyFromLocal();
        }

        private void CopyFromLocal()
        {
            var dirty = false;
            foreach (var info in files.SelectedItems.Cast<Info>())
            {
                if (info != null)
                {
                    var item = new FileInfo(Path.Combine(txtDirectoryName.Text, info.Name));
                    var blocks = item.Length / 1024 + (item.Length % 1024 == 0 ? 0 : 1);
                    var blocksFree = _disk.Directory.Entries.FirstOrDefault(x => x != null && x.Name != null && x.Name == "BLOCKS LEFT");
                    if (blocksFree != null && blocks <=
                        BitConverter.ToUInt16(blocksFree.DIR_MAX_LENGTH, 0))
                    {
                        _disk.AddFile(item.OpenRead(), item.Name + "\x3", DirectoryAttributes.UserFile);
                        dirty = true;
                    }
                    else if (blocksFree != null)
                    {
                        if (MessageBox.Show(this, "File too large.  Abort?", "ERROR", MessageBoxButton.YesNo) ==
                            MessageBoxResult.Yes)
                            break;
                    }
                    else if (blocks < _disk.TotalBlocks - _disk.Directory.Header.DIR_SIZE)
                    {
                        _disk.AddFile(item.OpenRead(), item.Name + "\x3", DirectoryAttributes.UserFile);
                        dirty = true;
                    }
                }
            }
            if (dirty)
            {
                var stream = File.OpenWrite(_adamFile);
                _disk.SaveFile(stream);
                stream.Close();
                GetAdamFiles(_adamFile);
            }
        }

        private void CopyFromAdam()
        {
            foreach (var item in adamFiles.SelectedItems.Cast<DirectoryEntry>())
            {
                var stream = File.OpenWrite(Path.Combine(txtDirectoryName.Text, item.Name));
                _disk.GetFile(item.Name, stream);
                stream.Flush(true);
                stream.Close();
            }

            LoadFiles();
        }

        private void F8_Tapped(object sender, RoutedEventArgs e)
        {
            if (_selected == adamFiles)
            {
                if (
                    MessageBox.Show(this, "Are you sure you want to delete these files?", "Confirm Delete",
                        MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                {
                    foreach (var entry in adamFiles.SelectedItems.Cast<DirectoryEntry>())
                    {
                        if (entry != null)
                        {
                            var stream = File.OpenWrite(_adamFile);
                            _disk.DeleteFile(stream, entry);
                            stream.Close();
                        }
                    }
                    GetAdamFiles(_adamFile);
                }
            }
            else
            {
                if (
                    MessageBox.Show(this, "Are you sure you want to delete these files?", "Confirm Delete",
                        MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                {
                    foreach (var info in files.SelectedItems.Cast<Info>())
                    {
                        if (info.Length != string.Empty)
                        {
                            var fi = new FileInfo(Path.Combine(txtDirectoryName.Text, info.Name));

                            fi.Delete();
                        }
                    }
                    LoadFiles();
                }
            }
        }

        private void F8_OnTapped(object sender, RoutedEventArgs e)
        {
            if (_selected == adamFiles && adamFiles.SelectedItem != null)
            {
                var entry = _disk.Directory.Entries.FirstOrDefault(x => x != null && x.Name == ((DirectoryEntry)adamFiles.SelectedItem).Name);

                if (entry != null)
                {
                    var dlg = new TextInputDialog
                    {
                        Caption = $"Rename {entry.Name}",
                        Message = "Choose a new name:",
                    };

                    if (dlg.ShowDialog() ?? false)
                    {
                        entry.Rename(dlg.Value);
                        var stream = File.OpenWrite(_adamFile);
                        _disk.SaveFile(stream);
                        stream.Close();
                        GetAdamFiles(_adamFile);
                    }
                }
            }
        }

        private void btnFindFolder_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new FolderBrowserDialog();

            var result = dlg.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                txtDirectoryName.Text = dlg.SelectedPath;

                var di = new System.IO.DirectoryInfo(dlg.SelectedPath);

                var list = di.GetDirectories().Select(x => new Info(x)).ToList();
                list.AddRange(di.GetFiles().Select(x => new Info(x)));

                _files = list;

                files.ItemsSource = _files;
            }
        }

        private void localfiles_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Selected = files;
        }

        private void btnUpDirectory_Click(object sender, RoutedEventArgs e)
        {
            if (txtDirectoryName.Text != string.Empty)
            {
                var di = new DirectoryInfo(txtDirectoryName.Text);
                var parent = di.Parent?.FullName;

                if (parent != null)
                {
                    txtDirectoryName.Text = parent;

                    LoadFiles();
                }
            }
        }

        private void LoadFiles()
        {
            if (txtDirectoryName.Text != string.Empty)
            {
                var di = new DirectoryInfo(txtDirectoryName.Text);
                var list = di.GetDirectories().Select(x => new Info(x)).ToList();
                list.AddRange(di.GetFiles().Select(x => new Info(x)));

                _files = list;

                files.ItemsSource = _files;
            }
        }

        private void files_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var info = files.SelectedItem as Info;

            if (info != null)
            {
                if (info.Length == string.Empty)
                {
                    txtDirectoryName.Text = Path.Combine(txtDirectoryName.Text, info.Name);
                    LoadFiles();
                }
                else
                {
                    if (info.Name.ToLower().EndsWith(".ddp")
                        || info.Name.ToLower().EndsWith(".dsk")
                        || info.Name.ToLower().EndsWith(".ds1")
                        || info.Name.ToLower().EndsWith(".ds2")
                        || info.Name.ToLower().EndsWith(".ds3")
                        )
                    {
                        _adamFile = Path.Combine(txtDirectoryName.Text, info.Name);
                        GetAdamFiles(_adamFile);
                    }
                }
            }
        }

        private void adamFiles_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Selected = adamFiles;
        }

        private void files_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Selected = files;
        }

        private void F10_Tapped(object sender, RoutedEventArgs e)
        {
            if (txtDirectoryName.Text != String.Empty)
            {
                var dlg = new NewImageDialog();
                dlg.Path = txtDirectoryName.Text;
                if (dlg.ShowDialog() ?? false)
                {
                    LoadFiles();
                    _adamFile = dlg.Result;
                    GetAdamFiles(_adamFile);
                }
            }
        }
    }

    internal class Info
    {
        public string Name { get; set; }
        public string Length { get; set; }
        public string Date { get; set; }

        public Info(FileInfo fi)
        {
            Name = fi.Name;
            Length = $"{fi.Length,11:N0}";
            Date = fi.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss");
        }

        public Info(DirectoryInfo di)
        {
            Name = di.Name;
            Length = "";
            Date = "";
        }

        public override string ToString()
        {
            if (Length != string.Empty)
                return $"{Length,11} {Date,18} {Name}";
            else
                return Name;
        }
    }
}
